package com.cloud.common.loadbalance;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 服务实例提供者
 *
 * @author fengwenjin
 */
@Slf4j
@Component
public class ServiceInstanceListProvider {
    private Set<String> serviceIds = new HashSet<>();
    private Map<String, List<ServiceInstance>> serviceInstanceMap = new ConcurrentHashMap<>();
    private ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
    private boolean executorRunning;

    @Autowired
    private DiscoveryClient discoveryClient;

    private synchronized void refreshServiceInstanceList() {
        if (executorRunning) {
            return;
        }
        executorRunning = true;

        // 定时获取服务实例列表
        executor.scheduleAtFixedRate(() -> {
            try {
                serviceIds.forEach(serviceId -> {
                    List<ServiceInstance> serviceInstanceList = discoveryClient.getInstances(serviceId);
                    serviceInstanceMap.put(serviceId, serviceInstanceList);
                });
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }, 3, 5, TimeUnit.SECONDS);
    }

    public List<ServiceInstance> get(String serviceId) {
        serviceIds.add(serviceId);
        List<ServiceInstance> serviceInstanceList = serviceInstanceMap.get(serviceId);
        if (serviceInstanceList == null) {
            refreshServiceInstanceList();
            serviceInstanceList = discoveryClient.getInstances(serviceId);
            serviceInstanceMap.put(serviceId, serviceInstanceList);
        }
        return serviceInstanceList;
    }

    public boolean exist(ServiceInstance serviceInstance) {
        List<ServiceInstance> instanceList = serviceInstanceMap.get(serviceInstance.getServiceId());
        if (CollectionUtils.isEmpty(instanceList)) {
            return false;
        }
        for (ServiceInstance instance : instanceList) {
            if (instance.getHost().equals(serviceInstance.getHost()) && instance.getPort() == serviceInstance.getPort()) {
                return true;
            }
        }
        return false;
    }
}
